Option Explicit

'################################################################
' Discriptor
' DFFilter 条件定义接口实现
' 单列的 [between] 比较
'################################################################

Implements IDFFilterColCondition

'################################################################
' Field
'################################################################
' 原始列，可以是真实列 DFFilterSingleCol 或者其他包装类型
Private originCol As IDFFilterCol

' 比较列数组
Private compareColArray() As Variant

'################################################################
' Constructor
'################################################################
Private Sub Class_Initialize()
End Sub

Private Sub Class_Terminate()
End Sub

'################################################################
' Init
'################################################################
' @param col 主计算列
' @param vs 比较列数组 IDFFilterCol[]
'                   每个数组元素的类型应该和 col 相容
'                   INT, DECIMAL 可以相容
'                   DF_DATE, DF_TIME, DF_TIMESTAMP 可以相容
Public Sub Init(ByRef col As IDFFilterCol, ByRef vs As Variant)
    ' 1. 检查参数
    ' 1.1 列不能为空
    If col Is Nothing Then
        Err.Raise 10001, Description:="parameter [col] must be not nothing"
        Exit Sub
    End If

    ' 1.2 列的类型不能是聚合列或组合式聚合列
    If col.isAggregateCol Then
        Err.Raise 10311, Description:="Aggregate Column Parameter [macolinCol] can not use in condition"
        Exit Sub
    End If

    ' 2. 检查比较数组参数
    ' 2.1 vs 必须是数组
    If IsArray(vs) = False Then
        Err.Raise 10005, Description:="parameter vs must be Array"
        Exit Sub
    End If

    ' 2.2 检查 vs 的数量
    Dim vsIdxMin As Integer
    Dim vsIdxMax As Integer
    Dim vsSize As Integer
    vsIdxMin = LBound(vs)
    vsIdxMax = UBound(vs)
    vsSize = vsIdxMax - vsIdxMin + 1
    If vsSize = 0 Then
        Err.Raise 10006, Description:="Array parameter vs's size must not be 0"
        Exit Sub
    End If

    ' 2.3 检查: vs 中的元素是否为空， col + vs 中各元素的类型是否匹配 的类型
    ReDim compareColArray(0 To (vsSize - 1)) As Variant

    Dim i As Integer
    Dim v As IDFFilterCol
    Dim valType As DF_DataType
    Dim colType As DF_DataType
    colType = col.ColType

    For i = 0 To (vsSize - 1)
        Set v = vs(vsIdxMin + i)

        If v Is Nothing Then
            Err.Raise 10001, Description:="parameter vs (" & i & ") must be not nothing"
            Exit Sub
        End If

        ' 检查类型是否相容
        valType = v.ColType

        If colType <> valType Then
            If (colType = DF_DataType.DF_INT Or colType = DF_DataType.DF_DECIMAL) And _
            (valType = DF_DataType.DF_INT Or valType = DF_DataType.DF_DECIMAL) Then
                ' 如果两者的类型是 INT 或 DECIMAL 则类型相容
                ' noop
            ElseIf (colType = DF_DataType.DF_DATE Or colType = DF_DataType.DF_TIME Or colType = DF_DataType.DF_TIMESTAMP) And _
                (valType = DF_DataType.DF_DATE Or valType = DF_DataType.DF_TIME Or valType = DF_DataType.DF_TIMESTAMP) Then
                ' noop
                    ' 如果两者的类型是 DF_DATE, DF_TIME, DF_TIMESTAMP 可以相容
            Else
                Err.Raise 10302, Description:="parameter type of col and vs(" & i & ") is not same: col Type=" & _
                                DFHelper.getDataTypeName(colType) & _
                                ", vs(" & i & ") Type=" & DFHelper.getDataTypeName(valType)
                Exit Sub
            End If
        End If

        ' 保存符合规则的比较数据
        Set fieldCompareVal(i) = v
    Next

    ' 3. 保存基本参数
    Set originCol = col
End Sub

'################################################################
' Function
'################################################################
' 检查 DFFilter 的活动行的数据是否符合规则
' 外部不应该主动调用
Public Function IDFFilterColCondition_unsafeCheckActiveRowVal() As Boolean
    ' 计算当前列的结果
    Dim curComputedVal As Variant
    curComputedVal = originCol.unsafeGetActiveRowVal()

    ' 和所有的比较数据进行比较，只要有一个符合规则，就停止并返回 True
    Dim tempCol As IDFFilterCol
    For Each tempCol In compareColArray
        If curComputedVal = v.unsafeGetActiveRowVal() Then
            IDFFilterColCondition_unsafeCheckActiveRowVal = True
            Exit Function
        End If
    Next

    IDFFilterColCondition_unsafeCheckActiveRowVal = False
End Function

' 返回当前条件是不是只使用了一个 Filter
Public Function IDFFilterColCondition_isUseSingleFilter() As Boolean
    ' 唯一返回 True 的组合
    ' 都不是字面量列，列的 Filter 都不是 Nothing，并且 Filter 相同
    Dim isNotAllLiteralCol As Boolean
    isNotAllLiteralCol = False
    Dim f As DFFilter

    ' 检查主列
    If Not originCol.isLiteralCol Then
        isNotAllLiteralCol = True
        If originCol.Filter Is Nothing Then
            ' 如果某个非字面量列使用 Filter 是多个，则立刻结束
            IDFFilterColCondition_isUseSingleFilter = False
            Exit Function
        End If

        ' 如果是第一次发现一个非字面量列，则保存这个列的 DFFilter
        Set f = originCol.Filter
    End If

    ' 检查所有比较列
    Dim tempCol As IDFFilterCol
    For Each tempCol In compareColArray
        If Not tempCol.isLiteralCol Then
            isNotAllLiteralCol = True
            If tempCol.Filter Is Nothing Then
                ' 如果某个非字面量列使用 Filter 是多个，则立刻结束
                IDFFilterColCondition_isUseSingleFilter = False
                Exit Function
            End If

            If f Is Nothing Then
                ' 如果是第一次发现一个非字面量列，则保存这个列的 DFFilter
                Set f = tempCol.Filter
            Else
                ' 如果是第 N 次发现一个非字面量列，则进行比较
                If Not f Is tempCol.Filter Then
                    IDFFilterColCondition_isUseSingleFilter = False
                    Exit Function
                End If
            End If
        End If
    Next

    IDFFilterColCondition_isUseSingleFilter = isNotAllLiteralCol
End Function

' 返回当前条件中是否使用了 Filter
' 因为存在如: And 1=1 这样的全字面量条件
Public Function IDFFilterColCondition_isUseFilter() As Boolean
    ' 如果 originCol + 所有比较列都是字面量列, 返回 False，只要有一个不是就返回 True
    If Not originCol.isLiteralCol Then
        IDFFilterColCondition_isUseFilter = True
        Exit Function
    End If

    Dim c As IDFFilterCol
    For Each c In compareColArray
        If Not c.isLiteralCol Then
            IDFFilterColCondition_isUseFilter = True
            Exit Function
        End If
    Next

    IDFFilterColCondition_isUseFilter = False
End Function

' 获取当前条件中使用的所有 Filter
' @return HashSet<DFFilter>
Public Function IDFFilterColCondition_getAllFilters() As ISet
    Set IDFFilterColCondition_getAllFilters = UtilsSet.createHashSet
    IDFFilterColCondition_getAllFilters.MergeSet originCol.getAllFilters

    Dim c As IDFFilterCol
    For Each c In compareColArray
        If Not c.isLiteralCol Then
            IDFFilterColCondition_getAllFilters.MergeSet c.getAllFilters
            Exit Function
        End If
    Next
End Function

' 检查当前条件使用的 DFFilter 是否和指定的 DFFilter 相同
' 如果条件中使用了多个 Filter，则返回 False
' 如果是全字面量列，则返回 False
Public Function IDFFilterColCondition_isSameFilter(ByRef filter As DFFilter) As Boolean
    ' 返回 True 的条件
    ' 不全是字面量列
    ' 非字面量的 isSameFilter 方法检查结果全部是 True

    ' 检查时，需要忽略其中的字面量列
    Dim isNotAllLiteralCol As Boolean
    isNotAllLiteralCol = False

    ' 检查主列
    If Not originCol.isLiteralCol Then
        isNotAllLiteralCol = True
        ' 如果左列的 isSameFilter 结果已经是 False，则立刻结束
        If originCol.isSameFilter(filter) = False Then
            IDFFilterColCondition_isSameFilter = False
            Exit Function
        End If
    End If

    ' 检查所有比较列
    Dim tempCol As IDFFilterCol
    For Each tempCol In compareColArray
        ' 检查主列
        If Not tempCol.isLiteralCol Then
            isNotAllLiteralCol = True
            ' 如果主列的 isSameFilter 结果已经是 False，则立刻结束
            If tempCol.isSameFilter(filter) = False Then
                IDFFilterColCondition_isSameFilter = False
                Exit Function
            End If
        End If
    Next

    ' 组合两个标识位
    ' 已完成以下组合为 True:
    '   不全是字面量列
    '   非字面量的 isSameFilter 方法检查结果全部是 True --> 能到达这里说明 isSameFilter 返回的全部是 True
    IDFFilterColCondition_isSameFilter = isNotAllLiteralCol
End Function